﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;

#endif
namespace com.susi.util.toolkit {
    //#if ODIN_INSPECTOR
    //    [LabelText("带事件列表"),ShowInInspector]
    //#endif
    public class EventStructList<T> where T : class { }

    /// <summary>
    /// 对List追加一层包装，以便于触发事件
    /// <br>当此对象<see cref="EventList{T}.IsDisposed"/>后，不能再对被包装的List进行操作</br>
    /// </summary>
    public class EventList<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList, IDisposable, IDisposaEventer, IDisposaEventer<EventList<T>>
        where T : class {
#if ODIN_INSPECTOR
        [ShowInInspector, ShowIf("IsDisposed")]
#endif
        public bool IsDisposed { get; private set; } = false;

        /// <summary>
        /// 对表进行一层包装。<see cref="InnerLst"/>
        /// </summary>
        /// <param name="value"></param>
        public EventList(IList<T> value)
        {
            if (value == null) throw new ArgumentNullException(nameof(value));
            this.InnerLst = value;
        }

        public EventList() : this(new List<T>()) { }

        public readonly IList<T> InnerLst; /*{ get; private set; }*/

        /// <summary>
        /// 当Dispose和Clear的时候最多只触发1次
        /// </summary>
        public event Action onChangedEvent;

        /// <summary>
        /// 总是保证触发
        /// </summary>
        public event Action<T> onAddedEvent;

        /// <summary>
        /// 总是保证触发
        /// </summary>
        public event Action<T> onRemovedEvent;

        /// <summary>
        /// args=item 返回false的时候终止Add操作
        /// </summary>
        public event Func<T, bool> onAddingFliter;

        /// <summary>
        /// args=item 返回false的时候终止操作
        /// <br>Clear和Dispose的时候会忽略Fliter</br>
        /// </summary>
        public event Func<T, bool> onRemovingFliterEvent;

        public event Action               onDisposingEvent;
        public event Action<EventList<T>> onDisposingTEvent;

        public bool IsDisposeAllItemOnDisposing = false;

        /// <summary>
        /// 性能低，最好用add和remove函数替代
        /// </summary>
        public T this[int index] {
            get => InnerLst[index];
            set {
                var og = this.InnerLst[index];
                if (og == null && value == null) {
                    return;
                }
                else if (og == null && value != null) {
                    if (!IsCrossAddingFliter(value)) return;
                    this.InnerLst[index] = value;
                    onAddedEvent?.Invoke(value);
                    onChangedEvent?.Invoke();
                }
                else if (og != null && value == null) {
                    if (!IsCrossRemovingFliter(og)) return;
                    this.InnerLst[index] = null;
                    onRemovedEvent?.Invoke(og);
                    onChangedEvent?.Invoke();
                }
                else if (og != null && value != null) {
                    if (!IsCrossRemovingFliter(og) || !IsCrossAddingFliter(value)) return;
                    this.InnerLst[index] = value;
                    onRemovedEvent?.Invoke(og);
                    onAddedEvent?.Invoke(value);
                    onChangedEvent?.Invoke();
                }
            }
        }

        public int Count => InnerLst.Count;

        public bool IsReadOnly => InnerLst.IsReadOnly;

        public bool IsFixedSize {
            get { return (InnerLst as IList)?.IsFixedSize ?? throw new NotSupportedException(); }
        }

        public bool IsSynchronized => ((ICollection) InnerLst).IsSynchronized;

        public object SyncRoot => ((ICollection) InnerLst).SyncRoot;

        object IList.this[int index] {
            get => this[index];
            set {
                if (!IsDisposed) this[index] = (T) value;
            }
        }

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和<see cref="onChangedEvent"/>
        /// </summary>
        public void Add(T item)
        {
            if (IsDisposed || !IsCrossAddingFliter(item)) return;
            InnerLst.Add(item);
            onAddedEvent?.Invoke(item);
            onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 在某些情形下，需要跳过过滤条件用
        /// 相比直接操作InnerList,这个可以触发AddedEvent和ChangedEvent
        /// </summary>
        public void AddWithoutFilter(T item)
        {
            if (IsDisposed) return;
            InnerLst.Add(item);
            onAddedEvent?.Invoke(item);
            onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和最多1次<see cref="onChangedEvent"/>
        /// </summary>
        public void AddRange(IEnumerable<T> ts)
        {
            if (IsDisposed || ts == null) return;
            bool ischanged = false;
            foreach (var item in ts) {
                if (!IsCrossAddingFliter(item)) continue;
                InnerLst.Add(item);
                onAddedEvent?.Invoke(item);
                ischanged = true;
            }

            if (ischanged) onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 无视Fliter进行清空
        /// 最多只触发一次onChang
        /// </summary>
        public void Clear()
        {
            var copy = InnerLst.ToArray();
            InnerLst.Clear();
            foreach (var item in copy) {
                onRemovedEvent?.Invoke(item);
            }

            if (copy.Length != 0) onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 清空所有可移除项目
        /// </summary>
        public void ClearWithFliter()
        {
            var  copy     = InnerLst.ToArray();
            bool isChange = false;
            foreach (var item in copy) {
                if (!IsCrossRemovingFliter(item)) continue;
                InnerLst.Remove(item);
                onRemovedEvent?.Invoke(item);
                if (!isChange) isChange = true;
            }

            if (isChange) onChangedEvent?.Invoke();
        }

        public bool Contains(T item)
        {
            return InnerLst.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            InnerLst.CopyTo(array, arrayIndex);
        }

        public IEnumerator<T> GetEnumerator()
        {
            return InnerLst.GetEnumerator();
        }

        public int IndexOf(T item)
        {
            return InnerLst.IndexOf(item);
        }

        /// <summary>
        /// 不通过或通过并触发<see cref="onAddedEvent"/>、<see cref="onChangedEvent"/>
        /// </summary>
        public void Insert(int index, T item)
        {
            if (!IsDisposed && !IsCrossAddingFliter(item)) return;
            InnerLst.Insert(index, item);
            onAddedEvent?.Invoke(item);
            onChangedEvent?.Invoke();
        }

        /// <summary>
        /// 不通过或同时触发<see cref="onRemovedEvent"/>、<see cref="onChangedEvent"/>
        /// </summary>
        public bool Remove(T item)
        {
            if (!IsCrossRemovingFliter(item)) return false;
            var res = InnerLst.Remove(item);
            if (res) {
                onRemovedEvent?.Invoke(item);
                onChangedEvent?.Invoke();
            }

            return res;
        }

        /// <summary>
        /// 没有移除任何元素返回false，否则返回true
        /// </summary>
        public bool RemoveRange(IEnumerable<T> ts)
        {
            if (IsDisposed && ts == null) return false;
            bool ischange = false;
            foreach (var item in ts) {
                if (!IsCrossRemovingFliter(item)) continue;
                var res = InnerLst.Remove(item);
                if (res) {
                    onRemovedEvent?.Invoke(item);
                    if (!ischange) ischange = true;
                }
            }

            if (ischange) onChangedEvent?.Invoke();
            return ischange;
        }

        public void RemoveAt(int index)
        {
            if (index > InnerLst.Count || index < 0) return;
            var it = InnerLst[index];
            if (it == null) return;
            if (!IsCrossRemovingFliter(it)) return;
            InnerLst.RemoveAt(index);
            onRemovedEvent?.Invoke(it);
            onChangedEvent?.Invoke();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return InnerLst.GetEnumerator();
        }

        private bool IsCrossAddingFliter(T item)
        {
            if (onAddingFliter == null) return true;
            foreach (Func<T, bool> func in onAddingFliter.GetInvocationList()) {
                if (func(item) == false) return false;
            }

            return true;
        }

        private bool IsCrossRemovingFliter(T item)
        {
            if (onRemovingFliterEvent == null) return true;
            foreach (Func<T, bool> func in onRemovingFliterEvent.GetInvocationList()) {
                if (func(item) == false) return false;
            }

            return true;
        }

        /// <summary>
        /// 不通过或者通过且同时触发<see cref="onAddedEvent"/>和<see cref="onChangedEvent"/>
        /// </summary>
        int IList.Add(object value)
        {
            if (!IsDisposed && !IsCrossAddingFliter((T) value)) return -1;
            var res = ((IList) this.InnerLst).Add(value);
            if (res != -1) {
                onAddedEvent?.Invoke((T) value);
                onChangedEvent?.Invoke();
            }

            return res;
        }

        public bool Contains(object value)
        {
            return this.InnerLst.Contains(value);
        }

        public int IndexOf(object value)
        {
            return this.InnerLst.IndexOf((T) value);
        }

        /// <summary>
        /// 类型强转到<see cref="Insert(int, T)"/>
        /// </summary>
        void IList.Insert(int index, object value)
        {
            this.Insert(index, (T) value);
        }

        /// <summary>
        /// 等同<see cref="Remove(T)"/>
        /// </summary>
        void IList.Remove(object value)
        {
            this.Remove((T) value);
        }

        public void CopyTo(Array array, int index)
        {
            ((ICollection) InnerLst).CopyTo(array, index);
        }

        /// <summary>
        /// 会调用一次<see cref="Clear"/>
        /// <para>即可能会触发多次<see cref="onRemovedEvent"/>和至多触发一次<see cref="onChangedEvent"/></para>
        /// <para>不会对里表和里表的所有元素执行Dispose，需要在DisposeEvent进行操作</para>
        /// </summary>
        public void Dispose()
        {
            if (IsDisposed) return;
            IsDisposed = true;
            onDisposingEvent?.Invoke();
            onDisposingTEvent?.Invoke(this);
            onDisposingEvent  = null;
            onDisposingTEvent = null;
            if (IsDisposeAllItemOnDisposing) {
                foreach (var item in InnerLst.ToArray()) {
                    (item as IDisposable)?.Dispose();
                }
            }

            Clear();
            onAddingFliter        = null;
            onRemovingFliterEvent = null;
            onAddedEvent          = null;
            onRemovedEvent        = null;
            onChangedEvent        = null;
        }
    }
}